很明显是一道高斯消元解线性异或方程组。

对于一个 n×mn\times m 的矩阵,我们给每个点编一个号,

对于第 ii行,第 jj 列的点,则有 p=(i1)×m+jp=(i-1)\times m+j

那么与它相邻的点的编号就出来了,

分别是 p1=pm,p2=p+m,p3=p1,p4=p+1p_1=p-m,p_2=p+m,p_3=p-1,p_4=p+1

那么对于每一个点,我们都可以列出一个方程式

xpxp1xp2xp3xp4=0x_p\oplus x_{p_1}\oplus x_{p_2}\oplus x_{p_3}\oplus x_{p_4}=0

那么 n×mn\times m 的矩阵就一共有 nmnm 个点,即我们需要列出一个 nmnm 元一次方程式组,

那这个方程组求出来的解就一定是答案吗?

不是,很明显,矩阵全部都为0也是这个方程组的一组合法解,

但题目又说了不能全为0,并且保证有解,那么就说明这个方程组并不是唯一解,

所以在跑完高斯消元后,对于那些自由元,我们全部赋值为1,这样就能求出答案了。

还有一个问题,这样做的时间复杂度是 O((nm)3)O((nm)^3) 的,

所以需要用bitset优化一下,就可以 O((nm)332)O(\frac{(nm)^3}{32}) 过了

不过似乎优化了还要慢一些

代码

#include<iostream>
#include<cstdio>
#include<bitset>
using namespace std;

bitset<2005> a[2005];
int n, x, y;

void gauss()
{
for (int r = 1, l = 1; l <= n; l++)
{
int t = r;
for (int i = r; i <= n; i++)
if (a[i][l])
t = i;
if (!a[t][l])
continue;
swap(a[t], a[r]);
for (int i = r + 1; i <= n; i++)
if (a[i][l])
a[i] = a[i] ^ a[r];
r++;
}
for (int i = n; i >= 1; i--)
{
if (!a[i][i])
a[i][n + 1] = 1;
else
for (int j = i + 1; j <= n; j++)
a[i][n + 1] = a[i][n + 1] ^ (a[i][j] & a[j][n + 1]);
}
}

int main()
{
scanf("%d%d", &x, &y);
n = x * y;
for (int i = 1; i <= x; i++)
{
for (int j = 1; j <= y; j++)
{
int p = (i - 1) * y + j;
int p1 = p - y, p2 = p + y, p3 = p - 1, p4 = p + 1;
if (i > 1) a[p][p1] = 1;
if (j > 1) a[p][p3] = 1;
if (i < x) a[p][p2] = 1;
if (j < y) a[p][p4] = 1;
a[p][p] = 1;
}
}
gauss();
for (int i = 1; i <= n; i++)
{
printf("%d ", (a[i][n + 1] ? 1 : 0));
if (i % y == 0)
printf("\n");
}
return 0;
}